
#ifndef CG_TLS_HPP
#define CG_TLS_HPP

#if defined(_MSC_VER)		// Visual C++ version

namespace cg
{
	/// Stores a thread-local value of type T.
	/** @param T is the type stored
		@param Tag is a type used to name different instances of T, if required
		\ingroup mem */
	template<typename T, typename Tag=T>
	class tls
	{
		static T & value()
		{
			static __declspec(thread) T value;
			return value;
		}

	public:
		static T get() { return value(); }
		static void set(T t) { value() = t; }
	};
}

#else

#include <pthread.h>

namespace cg
{
	/// Represents a single thread-local storage key for pthread.
	class tls_key : cg::not_copyable, cg::not_assignable
	{
		pthread_key_t m_key;
	public:
		tls_key()
		{
			if( pthread_key_create(&m_key, 0) )
				throw std::runtime_error("Error creating key");
		}

		~tls_key()
		{
			pthread_key_delete(m_key);
		}

		pthread_key_t get() const 
		{ 
			return m_key; 
		}
	};


	template<typename T, typename Tag=T>
	class tls;

	/// Stores a single threadsafe pointer.
	template<typename T, typename Tag>
	class tls<T*, Tag>
	{
		static pthread_key_t my_key()
		{
			static tls_key k;
			return k.get();
		}

	public:
		static T* get() 
		{ 
			return static_cast<T*>(pthread_getspecific( my_key() ));
		}

		static void set(T* v) 
		{ 
			pthread_setspecific( my_key(), static_cast<void*>(v) ); 
		}
	};
}

#endif

#endif
